\section{Hardwarerealisierung}
Der Realisierung dieses Subsystems lagen die im Unterkapitel \ref{sec:HW_Ziele} definierten Zwischenziele zugrunde.
\subsection{Geeignete Hardware}
Um das Subsystem mit seinen Funktionen zu entwickeln bedarf es eines Mikrocontrollers mit folgenden Modulen:
\begin{itemize}
\item Timer (Implementierung einer Uhr)
\item Analog/Digitalwandler (Digitalisierung der Messdaten)
\item UART (Kommunikation mit Modem)
\item JTAG (Eventuelle Fehlersuche)
\item Ausreichend RAM und ROM
\item ISP (Programmierung des Controllers)
\end{itemize}

Unter Berücksichtigung der Modulanforderungen fiel die Wahl auf einen AVR-ATMega-Mikrocontroller. Weitere Recherchen ergaben, dass ein Evaluationsboard ''AVR-NET-IO-Fertigmodul'' (vgl. Abbildung \ref{fig:IO-Board}) von der Firma ''Pollin'' mit einem ATMega32 auf dem Markt erhältlich ist. Dieses wurde über die Betreuer der Lehrveranstaltung beschafft.

\begin{figure}[ht]
	\centering
  \includegraphics[width=0.3\textwidth]{Bilder/AVR-IO_Draufsicht.jpg}
	\caption{AVR-NET-IO-Fertigmodul}
	\label{fig:IO-Board}
\end{figure}

Das Board enthält alle geforderten Hardwarebauteile (vgl. Abbildung \ref{fig:IO-Board_Schaltplan}) , um ohne weiteren Aufwand den Mikrocontroller mit einem CPU-Takt von \SI{16}{MHz} zu betreiben, den Mikrocontroller mit einem ''In-System-Programmer'' zu beschreiben, Analog/Digitalwandlungen durchzuführen und eine Kommunikation mit einem Modem über eine serielle Schnittstelle herzustellen.

Als Schnittstelle zu GSM-Netz wurde durch einen Betreuer ein ''Siemens S45'' Mobilfunktelefon (vgl. Abbildung \ref{fig:s45}) bereitgestellt. Dieses ist mit einem Adapterkabel an die serielle Schnittstelle des Boards angeschlossen.

\begin{figure}[ht]
	\centering
  \includegraphics[scale=1]{Bilder/s45.jpg}
	\caption{Siemens S45}
	\label{fig:s45}
\end{figure}

\begin{figure}[ht]
	\centering
  \includegraphics[width=0.8\textwidth]{Bilder/AVR-IO_Schaltplan.jpg}
	\caption{Schaltplan des AVR-NET-IO-Fertigmoduls}
	\label{fig:IO-Board_Schaltplan}
\end{figure}

Die zu messende analoge Spannung ist an den ADC1-Anschluss des Boards anzulegen. Dieser ist mit dem PA4 Pin des ATMega32 verbunden, hinter dem sich einer der acht AD-Wandler-Kanälen verbirgt.

\subsection{Timer und Uhr}
Die analogen Spannungswerte sollen sekündlich erfasst werden. Des Weiteren soll ein Zeitstempel mit dem Zeitpunkt des Versands einer SMS generiert werden. Für diese Zwecke wird das Modul "Timer1" des Mikrocontrollers verwendet. Dieser ist 16 Bit breit und kann so eingestellt werden, dass jede Sekunde ein Interrupt-Signal erzeugt wird.


\subsubsection{Timer}

Die Konfiguration des Timer1 erfolgt in der folgenden Funktion:
\lstset{language=C}
\begin{lstlisting}
bool bInitTimer(void) {
	// set up timer with prescaler = 256
	TCCR1B |= (1 << CS12) | (1 << WGM12);
	//load output compare register for an interrupt every 1s
	OCR1A = 62500;
	// initialize counter
	TCNT1 = 0;
	// enable overflow interrupt
	TIMSK |= (1 << OCIE1A);
	// enable global interrupts
	sei();
	return true;
}
\end{lstlisting}

Der CPU-Takt dient als Basis für den Zähler innerhalb des Timers. Mit dem Setzen des Vorteilers auf einen Wert von 256 wird erreicht, dass jeder 256-ste Takt der CPU eine Inkrementierung des Zählers zur Folge hat.

Als Nächstes wird ein Wert von 62500 in das Vergleichsregister geladen, um bei einem Zählerstand von 62500 einen Interrupt auszulösen und den Zähler zurück zu setzen. 

Nach Initialisierung des Zählers mit dem Wert 0 und Aktivierung der globalen Interrupts des Controllers ist die Initialisierung des Timers abgeschlossen.

Herleitung des Interrupttaktes:
\begin{equation}
\label{eg:Timer}
\text{Timerinterruptfrequenz}=\dfrac{\text{CPU-Takt}}{\text{Vorteiler}\cdot\text{Vergleichsregister}}=\dfrac{\SI{16}{MHz}}{256\cdot 62500}=\SI{1}{Hz}
\end{equation}

So wird erreicht, dass \lstinline$ISR(TIMER1_COMPA_vect)$ sekündlich ausgeführt wird. Innerhalb dieser ist folgendes implementiert:
\lstset{language=C}
\begin{lstlisting}
ISR(TIMER1_COMPA_vect)
{
	//increment seconds
	seconds++;
	//A/D conversion
	adc_val = ui16ReadADC(ADC_CHANNEL);
	//add adc_val to adc_val_sum <-- numerical integration
	adc_val_sum += adc_val;
	//inform main methode that one second is passed
	flag_second = 1;
}
\end{lstlisting}

In der Interruptserviceroutine wird die Sekundenvariable inkrementiert, die A/D-Wand- lung durchgeführt, der aktuelle AD-Wert zur Summe aller A/D-Werte über einen Zeitraum von 15 Minuten addiert und ein Flag gesetzt, welches einem anderen Programmteil über das Verstreichen einer Sekunde informiert.

Hervorzuheben ist die Kürze und Einfachheit der Routine. Sie führen zu einer schnellen Verarbeitung, um eventuelle Kollisionen mit anderen ISR's zu vermeiden.

Selbstverständlich sind alle in der Routine veränderten Variablen mit dem Schlüsselwort \lstinline$volatile$ deklariert. Dieses soll bewirken, dass die Variable immer im Speicher und nicht aus Optimierungsgründen in einem CPU-Register abgelegt werden. So ist es Sichergestellt das immer der aktuellste Wert im Speicher vorliegt.

\subsubsection{Uhrzeit und Datum}
In der Main-Methode wird innerhalb des kleinsten Betriebssystems der Welt, der \lstinline$while(1)$, das \lstinline$flag_second$ ausgewertet:
\lstset{language=C}
\begin{lstlisting}
	//check if second is passed
		if (flag_second) {
			//reset flag
			flag_second = 0;
			//check if minute is passed
			if (seconds >= 60) {
				//if passed reset seconds and increase minutes
				seconds = 0;
				minutes++;
				//check if 15 minutes passed
				if (!(minutes % 15)) {
					//if passed set flag
					flag15min = 1;
				}
				//check if hour is passed
				if (minutes >= 60) {
					//if passed reset minutes and increase hours
					minutes = 0;
					hours++;
					//check if day is passed
					if (hours >= 24) {
						//if passed reset hours and increase days
						hours = 0;
						day++;
						//check if february and no leap year is now
						if (day >= 29 && month == 2 && (year % 4)) {
							//if it is than reset days and increase month
							day = 1;
							month++;
							//check if years is over
							if (month >= 13) {
								//if over reset months and increase years
								month = 1;
								year++;
							}
							//check if february and leap year now,reset and increase then
						} else if (day >= 30 && month == 2 && !(year % 4)) {
							day = 1;
							month++;
							if (month >= 13) {
								month = 1;
								year++;
							}
							//check if the month has 31 days
						} else if (day >= 31 && (month == 4 || month == 6
								|| month == 9 || month == 11)) {
							day = 1;
							month++;
							if (month >= 13) {
								month = 1;
								year++;
							}
							//check if the month has 30 days
						} else if (day >= 32 && (month == 1 || month == 3
								|| month == 5 || month == 7 || month == 8
								|| month == 10 || month == 12)) {
							day = 1;
							month++;
							if (month >= 13) {
								month = 1;
								year++;
							}
						}
					}
				}
			}
\end{lstlisting}

Dieser Code-Abschnitt stellt ebenfalls die Implementierung der Uhr dar. Es wird neben der Uhrzeit auch das Datum implementiert. Dabei werden unterschiedliche Monatsdauern und Schaltjahre berücksichtigt.

\subsection{Analog/Digitalwandlung}
Wie aus dem vorherigen Abschnitt bekannt, wird die A/D-Wandlung durch den Aufruf von \lstinline$adc_val = ui16ReadADC(ADC_CHANNEL)$  jede Sekunde getriggert. Dazu wird der A/D-Wandler in der folgenden Funktion konfiguriert:
\lstset{language=C}
\begin{lstlisting}
bool bInitADC(void) {
	// AREF = AVcc
	ADMUX = (1 << REFS0);
	// ADC Enable and prescaler of 128
	// 16000000/128 = 125000
	ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
	return true;
}
\end{lstlisting}

Die am Port-Pin AVCC anliegenden \SI{5}{V} Versorgungsspannung des Controllers bilden die Referenz für den Wandlungsprozess. Der Vorteiler stellt den Takt des Wandlers auf \SI{125}{KHz}. Das ist die kleinste, einstellbare Frequenz oder der größte Vorteiler. Damit ist der Gesamtmessprozess langsamer, dafür wird eine höhere Genauigkeit erzielt.

Die Konvertierung wird folgendermaßen durchgeführt:

\lstset{language=C}
\begin{lstlisting}
uint16_t ui16ReadADC(uint8_t ch) {
	// select the corresponding channel 0~7
	// ANDing with '7' will always keep the value
	// of 'ch' between 0 and 7
	ch &= 0b00000111; // AND operation with 7
	ADMUX = (ADMUX & 0xF8) | ch; // clears the bottom 3 bits before ORing
	// start single convertion
	// write '1' to ADSC
	ADCSRA |= (1 << ADSC);
	// wait for conversion to complete
	// ADSC becomes '0' again
	// till then, run loop continuously
	while (ADCSRA & (1 << ADSC)) {
		;
	}
	return (ADC);
}
\end{lstlisting}

Der Funktion wird der ADC-Kanal übergeben, an welchem die Wandlung durchgeführt werden soll. Dieser wird innerhalb der Funktion ausgewählt und die Konvertierung gestartet. In einer Schleife wird gewartet bis der Konvertierungsprozess endet. Nach erfolgreicher Konvertierung wird ein Wert zwischen 0 und 1023, also 10 Bit breit, zurück gegeben.

\subsection{Datenstruktur}
Die Datenstruktur soll neben der Summen der sekündlich gemessenen Spannungswerte über einen Zeitraum von 15 Minuten einen Zeitstempel enthalten, der den Zeitpunkt des Transfers darstellt.

Hierfür wurde diese Struktur definiert:
\lstset{language=C}
\begin{lstlisting}
/*
 * sms_struct.h
 *
 *  Created on: 13.04.2012
 *      Author: Eugen Schneider
 */

#ifndef SMS_STRUCT_H_
#define SMS_STRUCT_H_

#include <stdbool.h>
#include <stdint.h>
#include <avr/io.h>

#define MAX_SMS_VALUES 24

struct current_time_and_date {
	uint8_t seconds;
	uint8_t minutes;
	uint8_t hours;
	uint8_t day;
	uint8_t month;
	uint8_t year;
}__attribute__ ((packed));

struct sms_payload {
	struct current_time_and_date time_and_date;
	uint16_t value[MAX_SMS_VALUES];
}__attribute__ ((packed));

#endif /* SMS_STRUCT_H_ */
\end{lstlisting}

Es handelt sich um eine Kombination aus Struktur und Array in einer Struktur. Zeit und Datum sind in der Struktur \lstinline$struct current_time_and_date$ definiert und repräsentieren mit jeweils 8 Bit die Sekunden, Minuten, Stunden, Tage, Monate und Jahre. Die Integrale über 15 Minuten werden in Form eines Array mit 24 Werten realisiert. Jeder Wert ist eine 16 Bit breite vorzeichenlose Ganzzahl.

Die Breite der Werte beruht auf der Tatsache, dass bei einer Integralbildung über 15 Minuten eines 10 Bit breiten Wertes ein maximaler Wert von $ Val_{\text{Max}}=1023\cdot60\cdot15=920700$ entstehen kann. Dieser ist 20 Bit breit, der jedoch um vier Stellen nach rechts verschoben maximal \SI{80}{mV} Ungenauigkeit aufweist, dafür aber weniger Speicherbedarf hat als ein 32 Bit breiter Wert, der die nächstgrößere Möglichkeit wäre.

Wie in Kapitel \ref{par:sms_aufbau} bereits beschrieben stehen 1120 Bit für den Transfer zur Verfügung. Die definierte Struktur ist 432 Bit groß. Man könnte also das doppelte an Werten übertragen und somit 50\% an SMS-Kosten sparen. Dieses ist aber aufgrund der verwendeten Codierung des Siemens S45 für SMS nicht möglich. Der Grund dafür wird in einem späteren Abschnitt erklärt.

\subsection{USART}
Zur Kommunikation mit dem Modem wird das USART-Modul des Mikrocontrollers eingesetzt. Nach Recherchen im Internet sind wir auf eine Bibliothek gestoßen, die die Kommunikation mit einem Siemens S45 sicherstellt. Der Autor der Bibliothek ist Lars Neubert.

Die Bibliothek besteht aus den Modulen SMS und UART, die jeweils in einer Header- und C-Datei implementiert sind.

Folgende Funktionen sind neben zahlreichen Definitionen und Variablen im Modul UART implementiert:
\lstset{language=C}
\begin{lstlisting}
extern void uart_init(void);
extern int uart_receive(FILE *dummy);
extern uint8_t uart_gets(char* buffer, uint8_t maxlen);
extern int uart_sendc(char c, FILE *dummy);
extern void uart_sends(char *s);
extern void uart_clear(void);
\end{lstlisting}

Die Funktionsnamen sind selbstredend. Alle Funktieonen finden im Modul SMS Verwendung.

\subsection{Befüllen, konvertieren und Versand der SMS}
Der folgende Codeabschnitt ist innerhalb der Main-Funktion implementiert. Eine Unterteilung in kleinere Funktionen wurde nicht in Betracht gezogen, um eventuelle Perfor- manceeinbußen durch Funktionsaufrufe zu vermeiden.

\lstset{language=C}
\begin{lstlisting}
	//check if 15 min passed
		if (flag15min) {
			//shift right to fit in 16 bit
			adc_val_sum = adc_val_sum >> 4;
			//store in struct
			sms.value[val_counter] = (uint16_t) (adc_val_sum);
			//reset flag and integral
			flag15min = 0;
			adc_val_sum = 0;
			//increase counter
			val_counter++;
			//check if preselected max amount vol is reached (24 for 6 hours)
			if (val_counter >= MAX_SMS_VALUES) {
				//generate timestamp
				sms.time_and_date.seconds = seconds;
				sms.time_and_date.minutes = minutes;
				sms.time_and_date.hours = hours;
				sms.time_and_date.day = day;
				sms.time_and_date.month = month;
				sms.time_and_date.year = year;
				//convert int to string
				char string[165] = "";
				char tmpstr[20] = "";
				sprintf(tmpstr, "%02X", sms.time_and_date.seconds);
				strcat(string, tmpstr);
				sprintf(tmpstr, "%02X", sms.time_and_date.minutes);
				strcat(string, tmpstr);
				sprintf(tmpstr, "%02X", sms.time_and_date.hours);
				strcat(string, tmpstr);
				sprintf(tmpstr, "%02X", sms.time_and_date.day);
				strcat(string, tmpstr);
				sprintf(tmpstr, "%02X", sms.time_and_date.month);
				strcat(string, tmpstr);
				sprintf(tmpstr, "%02X", sms.time_and_date.year);
				strcat(string, tmpstr);
				for (int var = 0; var < MAX_SMS_VALUES; ++var) {
					sprintf(tmpstr, "%04X", sms.value[val_counter]);
					strcat(string, tmpstr);
					sms.value[val_counter] = 0;
				}
				//send sms
				sms_send(SMS_TELNR, string);
				//reset valcounter
				val_counter = 0;

			}

		}
\end{lstlisting}

Der Block wird betreten, sobald das 15 Minuten-Flag gesetzt wird. Im Block wird die 32 Bit breite Integral-Variable \lstinline$adc_val_sum$ um vier Bits nach rechts verschoben, auf 16 Bit gecastet und in SMS-Struktur abgelegt.

Bei 24 abgelegten Werten wird ein Zeitstempel erzeugt und die Struktur in einen HEX-String konvertiert. Der HEX-String wächst dabei auf die doppelte Größe der SMS-Struktur an. Denn für die Darstellung als String, benötigt ein 8 Bit Wert 2 Chars, die selbst 8 Bit breit sind.

\subsection{Steuerung des Modems}
Für die Steuerung des Modems wurden AT-Befehle an das S45 gesandt. Zuerst wurden die Befehle direkt von einem Terminalprogramm mit 19200 Baud, 8 Bit Breite, ohne Parität und einem Stoppbit verschickt. Nach erfolgreichem Terminalbetrieb wurde das S45 an die USART des Controllers angeschlossen und mit Hilfe von der schon beschriebenen Bibliothek von Lars Neubert gesteuert. Zur Steuerung stehen folgende Funktionen zur Verfügung:
\lstset{language=C}
\begin{lstlisting}
extern uint8_t str2int(char data);

extern void sms_init(void);
extern void sms_time(unsigned char *year, unsigned char *month,
		unsigned char *day, unsigned char *hour, unsigned char *minute,
		unsigned char *secound);
extern void sms_send(char* zielnr, char* nachricht);
extern void sms_display_text(char* nachricht);
extern void sms_decode(char* pdu, SMS_DECODE_DATA_T* data);
extern uint8_t sms_check_nr(char* telnr_in);
extern SMS_MSG sms_state_machine(void);

extern uint8_t sms_cmdset(uint8_t dat);
\end{lstlisting}

Innerhalb der Initialisierung wird die UART des Controllers mit 19200 Baud, 8 Bit Breite, keiner Parität und einem Stoppbit initialisiert, die Standardausgabe des Controllers auf die UART geleitet.

Beim Versand der SMS wird der String in das PDU-Format konvertiert, da nur der Versand im Text-Modus mit dem S45 möglich ist. Dies bedeutet jedes Char wird einzeln um ein Bit nach links verschoben und alle an einander gefügt. Folgender Code veranschaulicht den Vorgang:
\lstset{language=C}
\begin{lstlisting}
	// Nachricht umwandeln in PDU-Format
	while (nachricht[cnt_txt] != 0) {
		if (shift == 7) {
			shift = 0;
			cnt_txt++;
			cnt_shiftzero++;
		} else {
			nachricht_neu[cnt_txt - cnt_shiftzero] = (((nachricht[cnt_txt]
					& 0x7F) >> shift) | ((nachricht[cnt_txt + 1])
					<< (7 - shift)));
			shift++;
			cnt_txt++;
		}
	}
	nachricht_neu[cnt_txt - cnt_shiftzero] = nachricht[cnt_txt]; // '0' anfuegen , Endestring
\end{lstlisting}





